package com.google.code.coma.logistics;

import com.google.code.coma.Coma;
import com.google.code.coma.domain.Computer;
import com.google.code.coma.domain.LifeCycleStep;
import com.google.code.coma.domain.Order;
import com.google.code.coma.rmi.ComputerSelector;
import com.google.code.coma.rmi.RMICallback;
import com.google.code.coma.rmi.RMIManager;
import com.google.code.coma.rmi.storage.StorageService;
import org.apache.log4j.Logger;

import java.rmi.NoSuchObjectException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.List;

/**
 */
public class RmiLogisticsWorker extends AbstractLogisticsWorker {
    private static final Logger log = Logger.getLogger(RmiLogisticsWorker.class);

    private StorageService<Computer> computerStorageService;

    private StorageService<Order> orderStorageService;

    private RMICallback<Computer> exportedCallback = null;

    private RMICallback<Computer> callback;

    public RmiLogisticsWorker(String factoryId) {
		super(factoryId);

        computerStorageService = RMIManager.getStorageService(factoryId + "_" + Coma.COMPUTER_CONTAINER);
        orderStorageService = RMIManager.getStorageService(factoryId + "_" + Coma.ORDER_CONTAINER);

        callback = new RMICallback<Computer>() {
            @Override
            public void handle(List<Computer> entries) throws RemoteException {
                Computer computer = entries.get(0);

                if (log.isInfoEnabled()) {
                    log.info("Finishing computer " + computer);
                }

                computer.changeState(LifeCycleStep.FINISHED, getWorkerId());

                if (computer.getOrder() != null) {
                    List<Computer> orderComputers = computerStorageService.getSnapshot(new ComputerSelector(computer.getOrder(), LifeCycleStep.FINISHED));

                    if ((orderComputers.size() + 1) == computer.getOrder().getSizeOfOrder()) {
                        computer.getOrder().finish();
                        orderStorageService.update(computer.getOrder());
                    }
                }

                computerStorageService.add(computer);
            }
        };
    }

    @Override
    public void startWork() {
        try {
            exportedCallback = (RMICallback<Computer>) UnicastRemoteObject.exportObject(callback, 0);
            computerStorageService.registerCallback(new ComputerSelector(LifeCycleStep.VERIFIED), callback);
        } catch (RemoteException e) {
            log.error("Error register callback", e);
        }
    }

    @Override
    public void stopWork() {
        if (exportedCallback != null) {
            try {
                UnicastRemoteObject.unexportObject(callback, false);
            } catch (NoSuchObjectException e) {
                log.error("Error unexporting object", e);
            } finally {
                exportedCallback = null;
            }
        }
    }

    @Override
    public boolean isActive() {
        return exportedCallback != null;
    }
}
